package com.alander.nexusgo.framework.log.starter.aspect;

import com.alander.nexusgo.framework.log.starter.autoconfigure.LogStatProperties;
import com.alander.nexusgo.framework.log.starter.model.RequestLog;
import com.alander.nexusgo.framework.log.starter.service.LogStatService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.Duration;
import java.time.Instant;

@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class LogStatAspect {

    private final LogStatProperties properties;

    private final LogStatService logStatService;

    @Around("execution(* com.alander.nexusgo..controller..*.*(..))")
    public Object aroundController(ProceedingJoinPoint joinPoint) throws Throwable {
        if (!properties.isEnabled()) {
            return joinPoint.proceed();
        }

        Instant start = Instant.now();

        // 获取请求信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = null;
        if (attributes != null) {
            request = attributes.getRequest();
        }

        String method = request.getMethod();
        String uri = request.getRequestURI();
        String ip = request.getRemoteAddr();
        Object[] args = joinPoint.getArgs();

        String params = null;
        if (properties.isLogRequestParams()) {
            params = args != null ? java.util.Arrays.toString(args) : null;
        }

        RequestLog logInfo = new RequestLog();
        logInfo.setTimestamp(java.time.LocalDateTime.now());
        logInfo.setMethod(method);
        logInfo.setUri(uri);
        logInfo.setIp(ip);
        logInfo.setParams(params);

        Object result = null;
        Throwable exception = null;

        try {
            result = joinPoint.proceed();
            return result;
        } catch (Throwable e) {
            exception = e;
            throw e;
        } finally {
            long duration = Duration.between(start, Instant.now()).toMillis();
            logInfo.setDuration(properties.isLogDuration() ? duration : null);
            logInfo.setResult(properties.isLogResponse() ? result : null);
            logInfo.setException(properties.isLogException() && exception != null ? exception.getMessage() : null);

            logStatService.log(logInfo);
        }
    }
}
